
#ifndef WIN32
#include <kos.h>
#define DBGOUT(string) printf(string);
#define DBGOUTP(string,x) printf(string,x);
#define O_BINARY 0
#endif

#ifdef WIN32
#include "../koswin/koswin.h"
#endif


#include <GL/gl.h>
#include <math.h>
#include "tgm.h"

#define DEGTORAD 0.0174532f
#define RADTODEG 57.2957795f



int load_tgm(char *filename, tgmmodel *obj)
{
	uint32 file;
	unsigned int cnt,i,objcnt;
	tgmXYZ tempXYZ;
	tgmUV tempUV;
	tgmTri tempTri;
	tgmOBJX tempOBJX;
	TGMHeader tgm_header;
	tgmmodel *currobj=obj;

//	DBGOUT("loading tgm...\r\n");
	i=0;
	currobj->numTri = 0;	
	currobj->numPt = 0;	
	currobj->numUV = 0;
	currobj->Tex=0;
	currobj->NextObj = 0;

	file = fs_open(filename, O_RDONLY|O_BINARY);

	if (!file) {
		DBGOUTP("Error opening %s \r\n",filename);
		return 1;
	}
	
	// load header
	cnt = fs_read(file, &tgm_header, sizeof(TGMHeader));
	if (tgm_header.ident!=TGM_MAGIC) {
		DBGOUT("invalid tgm file\r\n");
		return 1;
	}
//	DBGOUTP("num objx %i\r\n",tgm_header.numOBJX);

	//load xform
	for (objcnt=0;objcnt<tgm_header.numOBJX;objcnt++) {
		// load objx
		cnt = fs_read(file, &i, sizeof(i));//read magic
		if (i!=OBJX_MAGIC) {DBGOUT("objx unaligned\r\n"); return 1;}
		cnt = fs_read(file, &tempOBJX, sizeof(tempOBJX));
		currobj->ID = tempOBJX.ID;	
		currobj->numTri = tempOBJX.numTri;	
		currobj->numPt = tempOBJX.numPt;	
		currobj->numUV = tempOBJX.numUV;	
		currobj->boundmin.x=tempOBJX.Bounds.minx;
		currobj->boundmin.y=tempOBJX.Bounds.miny;
		currobj->boundmin.z=tempOBJX.Bounds.minz;
		currobj->boundmax.x=tempOBJX.Bounds.maxx;
		currobj->boundmax.y=tempOBJX.Bounds.maxy;
		currobj->boundmax.z=tempOBJX.Bounds.maxz;
		currobj->Tex=tempOBJX.Tex;

		currobj->scale.x=tempOBJX.XForm.sx;
		currobj->scale.y=tempOBJX.XForm.sy;
		currobj->scale.z=tempOBJX.XForm.sz;
		currobj->trans.x=tempOBJX.XForm.tx;
		currobj->trans.y=tempOBJX.XForm.ty;
		currobj->trans.z=tempOBJX.XForm.tz;
		currobj->transtx.x=tempOBJX.XForm.ttu;
		currobj->transtx.y=tempOBJX.XForm.ttv;
		currobj->scaletx.x=tempOBJX.XForm.stu;
		currobj->scaletx.y=tempOBJX.XForm.stv;

		currobj->tris = (triangle*)malloc(currobj->numTri * sizeof(triangle));
		currobj->points = (point*)malloc(currobj->numPt * sizeof(point));
		currobj->tvs = (texcoord*)malloc(currobj->numUV * sizeof(texcoord));
		//read tris
		cnt = fs_read(file, &i, sizeof(i));//read magic
		if (i!=TRIS_MAGIC) {DBGOUT("tris unaligned\r\n");fs_close(file);return 1;}
		for (i=0;i<currobj->numTri;i++) {
			cnt = fs_read(file, &tempTri, sizeof(tempTri));
			currobj->tris[i].a=tempTri.a;
			currobj->tris[i].b=tempTri.b;
			currobj->tris[i].c=tempTri.c;
			currobj->tris[i].tv1=tempTri.tv1;
			currobj->tris[i].tv2=tempTri.tv2;
			currobj->tris[i].tv3=tempTri.tv3;
		}

		//read pnts
		cnt = fs_read(file, &i, sizeof(i));//read magic
		if (i!=PNTS_MAGIC) {DBGOUT("points unaligned\r\n");fs_close(file);return 1;}
		for (i=0;i<currobj->numPt;i++) {
			cnt = fs_read(file, &tempXYZ, sizeof(tempXYZ));
			currobj->points[i].x=tempXYZ.x;
			currobj->points[i].y=tempXYZ.y;
			currobj->points[i].z=tempXYZ.z;
		}
		
		//read tvs
		cnt = fs_read(file, &i, sizeof(i));//read magic
		if (i!=TEXV_MAGIC) {DBGOUT("texverts unaligned\r\n");fs_close(file);return 1;}
		for (i=0;i<currobj->numUV;i++) {
			cnt = fs_read(file, &tempUV, sizeof(tempUV));
			currobj->tvs[i].u=tempUV.u;
			currobj->tvs[i].v=tempUV.v;
		}

		if (objcnt<(tgm_header.numOBJX-1)) {
			currobj->NextObj = malloc(sizeof(tgmmodel));
			currobj=(tgmmodel*)currobj->NextObj;
		}else{
			currobj->NextObj=0;
		}

	}
	fs_close(file);

//	DBGOUTP("loaded %s\r\n",filename);
//	DBGOUT("loaded tgm\r\n");

	return 0;
}

void draw_tgm(tgmmodel *tgm_model,uint32* textures) 
{
	unsigned short i;
	float tempx,tempy,tempz;
	tgmmodel* currobj=tgm_model;
	int currtex=-1,drawing=0;

	currobj=tgm_model;
	while (currobj!=0) {
		if ((int)currobj->Tex!=currtex) {
			if (drawing==1) {
				glEnd();
				drawing=0;
			}
			glBindTexture( GL_TEXTURE_2D, textures[currobj->Tex]);
#ifndef WIN32
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
			glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FILTER, GL_FILTER_BILINEAR);
#endif
			currtex=currobj->Tex;
		}

		if (drawing==0) {
			glBegin(GL_TRIANGLES);
			drawing=1;
		}
		for (i=0;i<currobj->numTri;i++)	{
			tempx=((float)currobj->points[currobj->tris[i].b].x)*currobj->scale.x+currobj->trans.x;
			tempy=((float)currobj->points[currobj->tris[i].b].y)*currobj->scale.y+currobj->trans.y;
			tempz=((float)currobj->points[currobj->tris[i].b].z)*currobj->scale.z+currobj->trans.z;
			glTexCoord2f(((float)currobj->tvs[currobj->tris[i].tv2].u)*currobj->scaletx.x+currobj->transtx.x, (((float)currobj->tvs[currobj->tris[i].tv2].v)*currobj->scaletx.y+currobj->transtx.y));
	//		glNormal3f(currobj->norms[currobj->tris[i]].nx, currobj->norms[currobj->tris[i]].ny, currobj->norms[currobj->tris[i]].nz);
			glVertex3f(tempx,tempy,tempz);

			
			glTexCoord2f(((float)currobj->tvs[currobj->tris[i].tv1].u)*currobj->scaletx.x+currobj->transtx.x, (((float)currobj->tvs[currobj->tris[i].tv1].v)*currobj->scaletx.y+currobj->transtx.y));
	//		glNormal3f(currobj->norms[currobj->tris[i]].nx, currobj->norms[currobj->tris[i]].ny, currobj->norms[currobj->tris[i]].nz);

			glVertex3f((((float)currobj->points[currobj->tris[i].a].x)*currobj->scale.x+currobj->trans.x)
				, (((float)currobj->points[currobj->tris[i].a].y)*currobj->scale.y+currobj->trans.y)
				, (((float)currobj->points[currobj->tris[i].a].z)*currobj->scale.z+currobj->trans.z));


			glTexCoord2f(((float)currobj->tvs[currobj->tris[i].tv3].u)*currobj->scaletx.x+currobj->transtx.x, (((float)currobj->tvs[currobj->tris[i].tv3].v)*currobj->scaletx.y+currobj->transtx.y));
	//		glNormal3f(currobj->norms[currobj->tris[i]].nx, currobj->norms[currobj->tris[i]].ny, currobj->norms[currobj->tris[i]].nz);
			glVertex3f((((float)currobj->points[currobj->tris[i].c].x)*currobj->scale.x+currobj->trans.x)
				, (((float)currobj->points[currobj->tris[i].c].y)*currobj->scale.y+currobj->trans.y)
				, (((float)currobj->points[currobj->tris[i].c].z)*currobj->scale.z+currobj->trans.z));

			
		}//endfor
		
		currobj=(tgmmodel*)currobj->NextObj;
	}//endwhile

	if (drawing==1) {
		glEnd();
		drawing=0;
	}
}

void draw_tgmLOD(tgmmodel *tgm_model,uint32* textures,vector* charpos,int clipobj,int cliptri,int clipz,int texcount) 
{
	unsigned short i,useclip=0;
	float tempx,tempy,tempz;
	tgmmodel* currobj=tgm_model;
	int currtex=-1,usetex,drawing=0;

	for (usetex=0;usetex<texcount;usetex++) {
		currobj=tgm_model;
		while (currobj!=0) {
			if ((int)currobj->Tex==usetex) {
				if(charpos->x<currobj->boundmax.x+clipobj && charpos->x>currobj->boundmin.x-clipobj &&
				charpos->y<currobj->boundmax.y+clipobj && charpos->y>currobj->boundmin.y-clipobj){
					if((int)currobj->Tex!=currtex) {
						if (drawing==1) {
							glEnd();
							drawing=0;
						}
						glBindTexture( GL_TEXTURE_2D, textures[currobj->Tex]);
#ifndef WIN32
						glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
						glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
						glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FILTER, GL_FILTER_BILINEAR);
#endif
						currtex=currobj->Tex;
					}

					if (drawing==0) {
						glBegin(GL_TRIANGLES);
						drawing=1;
					}
					for (i=0;i<currobj->numTri;i++)	{
						tempx=((float)currobj->points[currobj->tris[i].b].x)*currobj->scale.x+currobj->trans.x;
						tempy=((float)currobj->points[currobj->tris[i].b].y)*currobj->scale.y+currobj->trans.y;
						tempz=((float)currobj->points[currobj->tris[i].b].z)*currobj->scale.z+currobj->trans.z;
						if (
							tempy-charpos->y<cliptri &&
							tempy-charpos->y>-cliptri &&
							tempx-charpos->x<cliptri &&
							tempx-charpos->x>-cliptri &&
							tempz-charpos->z<cliptri &&
							tempz-charpos->z>-cliptri
							){
								if (tempy-charpos->y<clipz && tempy-charpos->y>-clipz && tempx-charpos->x<clipz && tempx-charpos->x>-clipz){
									if (useclip==0) {
#ifndef WIN32
										glEnable(GL_KOS_VFZ_CLIPPING);
#endif
										useclip=1;
									}
								}else{
									if (useclip==1) {
#ifndef WIN32
										glDisable(GL_KOS_VFZ_CLIPPING);
#endif
										useclip=0;
									}
								}
								glTexCoord2f(((float)currobj->tvs[currobj->tris[i].tv2].u)*currobj->scaletx.x+currobj->transtx.x, (((float)currobj->tvs[currobj->tris[i].tv2].v)*currobj->scaletx.y+currobj->transtx.y));
						//		glNormal3f(currobj->norms[currobj->tris[i]].nx, currobj->norms[currobj->tris[i]].ny, currobj->norms[currobj->tris[i]].nz);
								glVertex3f(tempx,tempy,tempz);

								
								glTexCoord2f(((float)currobj->tvs[currobj->tris[i].tv1].u)*currobj->scaletx.x+currobj->transtx.x, (((float)currobj->tvs[currobj->tris[i].tv1].v)*currobj->scaletx.y+currobj->transtx.y));
						//		glNormal3f(currobj->norms[currobj->tris[i]].nx, currobj->norms[currobj->tris[i]].ny, currobj->norms[currobj->tris[i]].nz);

								glVertex3f((((float)currobj->points[currobj->tris[i].a].x)*currobj->scale.x+currobj->trans.x)
									, (((float)currobj->points[currobj->tris[i].a].y)*currobj->scale.y+currobj->trans.y)
									, (((float)currobj->points[currobj->tris[i].a].z)*currobj->scale.z+currobj->trans.z));


								glTexCoord2f(((float)currobj->tvs[currobj->tris[i].tv3].u)*currobj->scaletx.x+currobj->transtx.x, (((float)currobj->tvs[currobj->tris[i].tv3].v)*currobj->scaletx.y+currobj->transtx.y));
						//		glNormal3f(currobj->norms[currobj->tris[i]].nx, currobj->norms[currobj->tris[i]].ny, currobj->norms[currobj->tris[i]].nz);
								glVertex3f((((float)currobj->points[currobj->tris[i].c].x)*currobj->scale.x+currobj->trans.x)
									, (((float)currobj->points[currobj->tris[i].c].y)*currobj->scale.y+currobj->trans.y)
									, (((float)currobj->points[currobj->tris[i].c].z)*currobj->scale.z+currobj->trans.z));

						}//endif-dist clip
					}//endfor
				}//if-in bounds
			}//tex check
			currobj=(tgmmodel*)currobj->NextObj;
		}//endwhile
	}//for draw by tex
	if (drawing==1) {
		glEnd();
		drawing=0;
	}
	if (useclip==1) {
#ifndef WIN32
		glDisable(GL_KOS_VFZ_CLIPPING);
#endif
		useclip=0;
	}
}

void draw_tgm_byID(tgmmodel *tgm_model,uint32* textures,int ID,int texcount) 
{
	int i,currtex=-1,usetex,drawing=0;

	tgmmodel* currobj=tgm_model;
	for (usetex=0;usetex<texcount;usetex++) {
		currobj=tgm_model;
		while (currobj!=0) {
			if ((int)currobj->Tex==usetex && (int)currobj->ID==ID) {//ID and tex check
				if((int)currobj->Tex!=currtex) {
					if (drawing==1) {
						glEnd();
						drawing=0;
					}
					glBindTexture( GL_TEXTURE_2D, textures[currobj->Tex]);
#ifndef WIN32
					glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
					glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
					glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_FILTER, GL_FILTER_BILINEAR);
#endif
					currtex=currobj->Tex;
				}

				if (drawing==0) {
					glBegin(GL_TRIANGLES);
					drawing=1;
				}
				for (i=0;(unsigned int)i<currobj->numTri;i++)	{
					glTexCoord2f(((float)currobj->tvs[currobj->tris[i].tv2].u)*currobj->scaletx.x+currobj->transtx.x, (((float)currobj->tvs[currobj->tris[i].tv2].v)*currobj->scaletx.y+currobj->transtx.y));
			//		glNormal3f(currobj->norms[currobj->tris[i]].nx, currobj->norms[currobj->tris[i]].ny, currobj->norms[currobj->tris[i]].nz);
					glVertex3f(((float)currobj->points[currobj->tris[i].b].x)*currobj->scale.x+currobj->trans.x
						,((float)currobj->points[currobj->tris[i].b].y)*currobj->scale.y+currobj->trans.y
						,((float)currobj->points[currobj->tris[i].b].z)*currobj->scale.z+currobj->trans.z);

					
					glTexCoord2f(((float)currobj->tvs[currobj->tris[i].tv1].u)*currobj->scaletx.x+currobj->transtx.x, (((float)currobj->tvs[currobj->tris[i].tv1].v)*currobj->scaletx.y+currobj->transtx.y));
			//		glNormal3f(currobj->norms[currobj->tris[i]].nx, currobj->norms[currobj->tris[i]].ny, currobj->norms[currobj->tris[i]].nz);

					glVertex3f((((float)currobj->points[currobj->tris[i].a].x)*currobj->scale.x+currobj->trans.x)
						, (((float)currobj->points[currobj->tris[i].a].y)*currobj->scale.y+currobj->trans.y)
						, (((float)currobj->points[currobj->tris[i].a].z)*currobj->scale.z+currobj->trans.z));


					glTexCoord2f(((float)currobj->tvs[currobj->tris[i].tv3].u)*currobj->scaletx.x+currobj->transtx.x, (((float)currobj->tvs[currobj->tris[i].tv3].v)*currobj->scaletx.y+currobj->transtx.y));
			//		glNormal3f(currobj->norms[currobj->tris[i]].nx, currobj->norms[currobj->tris[i]].ny, currobj->norms[currobj->tris[i]].nz);
					glVertex3f((((float)currobj->points[currobj->tris[i].c].x)*currobj->scale.x+currobj->trans.x)
						, (((float)currobj->points[currobj->tris[i].c].y)*currobj->scale.y+currobj->trans.y)
						, (((float)currobj->points[currobj->tris[i].c].z)*currobj->scale.z+currobj->trans.z));
				}//endfor
			}//by ID
			currobj=(tgmmodel*)currobj->NextObj;
		}//endwhile
	}
	if (drawing==1) {
		glEnd();
		drawing=0;
	}

}

void free_tgm(tgmmodel *tgm_model) 
{
	tgmmodel* currobj;
	tgmmodel* oldobj;
	currobj=tgm_model;
	while (currobj!=0) {
		if (currobj->points) free(currobj->points);
		if (currobj->tvs) free(currobj->tvs);
	//	if (currobj->norms) free(currobj->norms);
		if (currobj->tris) free(currobj->tris);
		oldobj=currobj;
		currobj=(tgmmodel*)currobj->NextObj;
		if (oldobj!=tgm_model) {if (oldobj) free(oldobj);}
	}

}
